﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using System.Xml.Serialization;
using System.Runtime.Serialization;

namespace MazeWars
{
    class TutorialWindow : Window
    {
        Vector2[] offset;
        Viewport playerOne, playerTwo, spellEffects;
        Texture2D tileSprites, cooldownSprites, bkgd, cursor;
        Texture2D pOnePortrait, pTwoPortrait;
        Rectangle drawRect, cursorSrcRect;
        List<Trunk> trunks;
        List<Trunk> trunks2;
        Vector2 dest;
        Vector2 cursorLoc, cursorLoc2;
        SpriteFont font;
        Player[] player;
        int row, col, counter, subcounter;
        int p1Health, p2Health;
        float dt;

        const int TILE_WIDTH = 64;
        const int TILE_HEIGHT = 64;

        public TutorialWindow()
        {
            p1Health = p2Health = 100;
            dt = 0;
            row = col = counter = subcounter = 0;
            offset = new Vector2[2];
            offset[0] = Vector2.Zero;
            offset[1] = Vector2.Zero;
            dest = Vector2.Zero;
            drawRect = new Rectangle(0, 0, TILE_WIDTH, TILE_HEIGHT);
            cursorSrcRect = new Rectangle(0, 0, TILE_WIDTH, TILE_HEIGHT);
            player = new Player[2];
            player[0] = new Player();
            player[1] = new Player();
        }

        public override void setupWindow(ContentManager cm, Viewport vp)
        {
            tileSprites = cm.Load<Texture2D>("Alpha_TilePallet");
            cooldownSprites = cm.Load<Texture2D>("Alpha_ColdTilePallet");
            bkgd = cm.Load<Texture2D>("MazeMenu04");
            cursor = cm.Load<Texture2D>("gamecursor");
            pOnePortrait = cm.Load<Texture2D>("GSP1");
            pTwoPortrait = cm.Load<Texture2D>("GSP2");
            font = cm.Load<SpriteFont>("Times New Roman");

            playerOne = vp;
            playerTwo = vp;
            spellEffects = vp;
            playerOne.Height = vp.Height * 3 / 4;
            playerOne.Width = vp.Width / 2;
            playerTwo.Height = vp.Height * 3 / 4;
            playerTwo.Width = vp.Width / 2;
            playerTwo.X = vp.Width / 2;
            spellEffects.Height = vp.Height / 4;
            spellEffects.Width = vp.Width;
            spellEffects.Y = vp.Height * 3 / 4;
            cursorLoc = new Vector2(playerOne.Width / 2, playerOne.Height / 2);
            cursorLoc2 = new Vector2(playerTwo.Width / 2, playerTwo.Height / 2);
        }

        public override void draw(SpriteBatch sb, GraphicsDevice gd)
        {
            //Player One's side of the screen
            gd.Viewport = playerOne;
            gd.Clear(Color.TransparentWhite);
            sb.Begin(SpriteBlendMode.AlphaBlend);
            sb.Draw(bkgd, new Rectangle(0, 0, playerOne.Width, playerOne.Height), new Rectangle(0, 0, bkgd.Width / 2, bkgd.Height * 3 / 4), Color.White);
            switch (counter)
            {
                case 3:
                    {
                        foreach (Trunk t in trunks)
                        {
                            foreach (Tile tile in t.TrunkTiles)
                            {
                                dest = tile.Pos + cursorLoc + offset[0];
                                if (t == trunks[0])
                                {
                                    sb.Draw(tileSprites, dest, tile.FinalSrcRect, Color.White);
                                }
                                else
                                {
                                    sb.Draw(cooldownSprites, dest, tile.FinalSrcRect, Color.White);
                                }
                            }
                        }
                    } break;
                case 5:
                    {
                        foreach (Trunk t in trunks)
                        {
                            foreach (Tile tile in t.TrunkTiles)
                            {
                                dest = tile.Pos + cursorLoc + offset[0];
                                if (t == trunks[1])
                                {
                                    sb.Draw(tileSprites, dest, tile.FinalSrcRect, Color.White);
                                }
                                else
                                {
                                    sb.Draw(cooldownSprites, dest, tile.FinalSrcRect, Color.White);
                                }
                            }
                        }
                    } break;
                case 13:
                case 14:
                case 15:
                    {
                        foreach (Trunk t in trunks)
                        {
                            foreach (Tile tile in t.TrunkTiles)
                            {
                                dest = tile.Pos + cursorLoc + offset[0];
                                if (t == trunks[1])
                                {
                                    sb.Draw(cooldownSprites, dest, tile.FinalSrcRect, Color.White);
                                }
                                else
                                {
                                    sb.Draw(tileSprites, dest, tile.FinalSrcRect, Color.White);
                                }
                            }
                        }
                    } break;
                default:
                    {
                        foreach (Trunk t in trunks)
                        {
                            foreach (Tile tile in t.TrunkTiles)
                            {
                                dest = tile.Pos + cursorLoc + offset[0];
                                sb.Draw(tileSprites, dest, tile.FinalSrcRect, Color.White);
                            }
                        }
                    } break;
            }
        
            sb.Draw(cursor, cursorLoc, cursorSrcRect, Color.White);
            sb.End();


            //Player Two's side of the screen
            gd.Viewport = playerTwo;
            gd.Clear(Color.TransparentWhite);
            sb.Begin(SpriteBlendMode.AlphaBlend);
            sb.Draw(bkgd, new Rectangle(0, 0, playerTwo.Width, playerTwo.Height), new Rectangle(bkgd.Width / 2, 0, bkgd.Width / 2, bkgd.Height * 3 / 4), Color.White);
            foreach (Trunk t in trunks2)
            {
                foreach (Tile tile in t.TrunkTiles)
                {
                    dest = tile.Pos + cursorLoc2 + offset[1];
                    if (t.OnCooldown)
                    {
                        sb.Draw(cooldownSprites, dest, tile.FinalSrcRect, Color.White);
                    }
                    else
                    {
                        sb.Draw(tileSprites, dest, tile.FinalSrcRect, Color.White);
                    }
                }
            }
            sb.Draw(cursor, cursorLoc2, cursorSrcRect, Color.White);
            sb.End();

            //Bottom of the screen - portraits, health, spell effects, etc.
            gd.Viewport = spellEffects;
            gd.Clear(Color.TransparentWhite);
            sb.Begin(SpriteBlendMode.AlphaBlend);
            sb.Draw(bkgd, new Rectangle(0, 0, spellEffects.Width, spellEffects.Height), new Rectangle(0, bkgd.Height * 3 / 4, bkgd.Width, bkgd.Height / 4), Color.White);
            sb.Draw(pOnePortrait, new Rectangle(0, 0, pOnePortrait.Width, spellEffects.Height), Color.White);
            sb.Draw(pTwoPortrait, new Rectangle(spellEffects.Width - pTwoPortrait.Width, 0, pTwoPortrait.Width, spellEffects.Height), Color.White);
            sb.DrawString(font, p1Health.ToString(), new Vector2(pOnePortrait.Width + 20, 0), Color.Black);
            sb.DrawString(font, p2Health.ToString(), new Vector2(spellEffects.Width - pTwoPortrait.Width - 120, 0), Color.Black);
            sb.End();
        }

        public override void update(KeyboardState ks, GameTime gameTime)
        {
            col++;
            col %= 59;
            cursorSrcRect.X = col * TILE_WIDTH;

            dt += gameTime.ElapsedGameTime.Milliseconds / 1000.0f;
            
            switch (counter)
            {
                case 0: SoundManager.Instance().PlayCue(0, "tutorial01"); counter++; break;
                case 1: if(!SoundManager.Instance().IsPlaying("tutorial01")){counter++;} break;
                case 2: SoundManager.Instance().PlayCue(0, "tutorial02"); counter++; break;
                case 3: if (!SoundManager.Instance().IsPlaying("tutorial02")) { counter++; } break;
                case 4: SoundManager.Instance().PlayCue(0, "tutorial03"); counter++; break;
                case 5: if (!SoundManager.Instance().IsPlaying("tutorial03")) { counter++; } break;
                case 6: if (dt > 0.5f)
                    {
                        dt = 0;
                        subcounter++;
                        offset[0].X -= 64;
                        if (subcounter == 2)
                        {
                            counter++;
                            subcounter = 0;
                        }
                    } break;
                case 7: SoundManager.Instance().PlayCue(0, "tutorial04"); counter++; break;
                case 8: if (!SoundManager.Instance().IsPlaying("tutorial04")) { counter++; } break;
                case 9: if (dt > 0.5f)
                    {
                        dt = 0;
                        subcounter++;
                        if (subcounter < 6)
                        {
                            offset[0].Y += 64;
                        }
                        else if (subcounter < 10)
                        {
                            offset[0].X += 64;
                        }
                        else
                        {
                            counter++;
                            subcounter = 0;
                        }
                    } break;
                case 10: SoundManager.Instance().PlayCue(0, "tutorial05"); counter++; break;
                case 11: if (!SoundManager.Instance().IsPlaying("tutorial05")) { counter++; } break;
                case 12: if (dt > 0.5f)
                    {
                        dt = 0;
                        subcounter++;
                        if (subcounter < 5)
                        {
                            offset[0].X -= 64;
                        }
                        else if (subcounter < 10)
                        {
                            offset[0].Y -= 64;
                        }
                        else
                        {
                            counter++;
                            p2Health -= 15;
                            subcounter = 0;
                        }
                    } break;
                case 13: SoundManager.Instance().PlayCue(0, "tutorial06"); counter++; break;
                case 14: if (!SoundManager.Instance().IsPlaying("tutorial06")) { dt = 0; counter++; } break;
                case 15: if (dt > 2.0f) { WindowManager.instance().changeWindow(Window.BATTLE_WINDOW); } break;
            }
        }

        public override void loadWindow()
        {
            trunks = loadTrunks();
            trunks2 = loadTrunks();
            player[0].populateTree(trunks);
            player[1].populateTree(trunks2);
            randomizeTiles();
        }

        private void randomizeTiles()
        {
            Random random = new Random();
            List<Tile> playerTrunkTiles;
            List<Tile> prevTrunkTiles;
            Point p = new Point(0, 0);
            int num;
            int nodeNum = -1;

            for (int j = 0; j < 2; j++)
            {
                playerTrunkTiles = player[j].TrunkList[0].TrunkTiles;
                for (int k = 0; k < player[j].TrunkList.Count; k++)
                {
                    foreach (Trunk trunkItr in player[j].TrunkList)
                    {
                        if ((nodeNum = player[j].getNode(k, trunkItr)) != -1)
                        {
                            break;
                        }
                    }

                    prevTrunkTiles = player[j].prevTrunk(k).TrunkTiles;

                    for (int i = 0; i < player[j].TrunkList[k].TrunkTiles.Count; i++)
                    {
                        while (true)
                        {
                            num = random.Next() % 8;

                            if (k > 0 && i == 0)
                            {
                                if (nodeNum == 0)
                                {
                                    if (prevTrunkTiles[nodeNum + 1].Button != num)
                                    {
                                        break;
                                    }
                                }
                                else if (nodeNum == prevTrunkTiles.Count - 1)
                                {
                                    if (prevTrunkTiles[nodeNum - 1].Button != num)
                                    {
                                        break;
                                    }
                                }
                                else if (prevTrunkTiles[nodeNum - 1].Button != num && prevTrunkTiles[nodeNum + 1].Button != num)
                                {
                                    break;
                                }
                            }
                            else if (k > 0 && i == 1 && prevTrunkTiles[nodeNum].Button != num)
                            {
                                break;
                            }
                            else if ((k == 0 && i <= 1) || (i > 1 && player[j].TrunkList[k].TrunkTiles[i - 2].Button != num))
                            {
                                break;
                            }
                        }
                        switch (num)
                        {
                            case 0: p.X = 0; p.Y = 0; break;
                            case 1: p.X = 64; p.Y = 0; break;
                            case 2: p.X = 128; p.Y = 0; break;
                            case 3: p.X = 192; p.Y = 0; break;
                            case 4: p.X = 0; p.Y = 64; break;
                            case 5: p.X = 64; p.Y = 64; break;
                            case 6: p.X = 128; p.Y = 64; break;
                            case 7: p.X = 192; p.Y = 64; break;
                        }
                        player[j].TrunkList[k].TrunkTiles[i].Button = num;
                        player[j].TrunkList[k].TrunkTiles[i].Offset = p;
                    }
                }
            }
        }

        private List<Trunk> loadTrunks()
        {
            List<Trunk> tempList = new List<Trunk>();
            FileStream file = OpenTitleFile("trunks.xml", FileMode.Open);

            if (file != null)
            {
                try
                {
                    XmlSerializer xml = new XmlSerializer(typeof(List<Trunk>));
                    tempList = (List<Trunk>)xml.Deserialize(file);
                }
                catch (SerializationException e)
                {
                    byte[] errorMsg = new byte[128];
                    for (int i = 0; i < e.Message.Length; i++)
                    {
                        errorMsg[i] = (byte)e.Message[i];
                    }
                    FileStream error = OpenTitleFile("error.txt", FileMode.Create);
                    error.Write(errorMsg, 0, e.Message.Length > 128 ? 128 : e.Message.Length);
                    error.Close();
                }
                finally
                {
                    file.Close();
                    file.Dispose();
                }
            }
            return tempList;
        }

        private static FileStream OpenTitleFile(string filename, FileMode mode)
        {
            string fullpath = Path.Combine(StorageContainer.TitleLocation, filename);

            if (mode != FileMode.Create)
            {
                if (!File.Exists(fullpath))
                {
                    return null;
                }
            }

            return File.Open(fullpath, mode);
        }
    }
}
